﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Net.Sockets;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Collections;
using Matrix_ClassLibrary;
using System.Windows.Forms;

namespace LTTT_server
{
    class ConnectionServer
    {
        public delegate void DoSomeThingMethod(string message);
        public event DoSomeThingMethod ProcessAfterReceiveMessage;
        byte[] data = new byte[1024]; // mãng data chứa dữ liệu
        bool IsReceived = true;
        Socket server,client;
        string address;
        string ReceiveMessage = String.Empty;
        public ConnectionServer(string address)
        {
            this.address = address;
            
        }
        // Hàm khởi động server
        public void StartServer()
        {
            IPEndPoint ipe = new IPEndPoint(IPAddress.Parse(address), 30000);
            server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                server.Bind(ipe);
            }
            catch
            {
                throw new ArgumentNullException("socket", "Socket da ton tai");
            }
            server.Listen(10);
            server.BeginAccept(new AsyncCallback(CallAccept), server);
        }
        // Hàm ngưng Server
        public void StopServer()
        {
           // server.Shutdown(SocketShutdown.Both);
            server.Close();
        }
        // Hàm bất đồng bộ chờ kết nối đến
        public void CallAccept(IAsyncResult air)
        {
            try
            {
                server = (Socket)air.AsyncState;
                client = server.EndAccept(air);
            }
            catch
            {
                return;
            }
        }
        /// <summary>
        /// Hàm Gửi dữ liệu đi client
        /// </summary>
        /// <param name="message">thông điêp dạng byte</param>
        public void SendData(byte[] message)
        {
            try
            {
                client.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(SendData), client);
            }
            catch (Exception ex)
            {
                throw new Exception("Không thể gửi được cho client !");
            }
        }
        // Hàm bất đồng bộ gửi dữ liệu đi
        private void SendData(IAsyncResult air)
        {
            client = (Socket)air.AsyncState;
            client.EndSend(air);
            client.BeginReceive(data, 0, data.Length, SocketFlags.None, new AsyncCallback(RecieveData), client);
        }
        // Hàm bất đồng bộ nhận dữ liệu trả về
        public void RecieveData(IAsyncResult air)
        {
            client = (Socket)air.AsyncState;
            int recieve = client.EndReceive(air);
            IsReceived = true;
            try
            {
                if (recieve == 0)
                {
                    client.Close(); // đóng kết nối
                    server.BeginAccept(new AsyncCallback(CallAccept), server);
                    return;
                }
            }
            catch
            {
                server.BeginAccept(new AsyncCallback(CallAccept), server);
            }
            
            ReceiveMessage = Encoding.UTF8.GetString(data,0,recieve);
            // Giọi sự kiện xử lý quá trình trả về ở Form
            ProcessAfterReceiveMessage(ReceiveMessage);
            
        }
        // Hàm gửi ma trận qua cho client
        public void SendMatrix(Matrix matrix)
        {
            if (IsReceived == false) return;
            try
            {
                MemoryStream stream = new MemoryStream();
                // Phần đầu của message, nó cho client biết đây là ma trận vì là 0
                byte[] header = Encoding.UTF8.GetBytes("0");

                // Phần thân của thông điệp được serialize và chuyển sang dạng byte
                IFormatter formatter2 = new BinaryFormatter();
                formatter2.Serialize(stream, matrix);
                byte[] body = stream.GetBuffer();
                // kết hợp header và body
                byte[] message = CombineByteArray(header, body);
                // gửi message đi
                SendData(message);
                stream.Close(); // đóng kết nối
                // Set lại biến IsReceived = false để chờ nhận
                IsReceived = false;
            }
            catch(Exception e)
            {
                // Gui thất bại, set IsReceive về true để gửi lại
                IsReceived = true;
                throw new Exception(e.Message);
            }
           
        }
        // Hàm gửi thông điệp U dạng sting
        public void SendMessage(string message)
        {
            try
            {
                if (IsReceived == false) return;
                byte[] msg = Encoding.UTF8.GetBytes("1" + message);
                SendData(msg);
                // Set lại biến IsReceived = false để chờ nhận
                IsReceived = false;
            }
            catch(Exception e)
            {
                // Gui thất bại, set IsReceive về true để gửi lại
                IsReceived = true;
                throw new Exception(e.Message);
            }
        }
        // hàm accestor lấy thông điệp nhận được
        public string ReceiveMessages
        {
            get
            {
                return ReceiveMessage;
            }
        }
        // Nối 2 dãy byte lại với nhau
        public byte[] CombineByteArray(byte[] a1, byte[] a2)
        {
             byte[] ret = new byte[a1.Length + a2.Length];
            Array.Copy(a1, 0, ret, 0, a1.Length);
            Array.Copy(a2, 0, ret, a1.Length, a2.Length);
            return ret;
        }
    }
}
